﻿using System;
using System.Collections.Generic;
using System.Data;
using zijian666.Core;
using System.Linq;

namespace zijian666.Data
{
    /// <summary>
    /// 数据库查询参数占位符提供程序
    /// </summary>
    public class DbParamPlaceholderProvider : IDbParamPlaceholderProvider
    {
        private readonly Func<IDataParameter, string> _placeholder;
        /// <summary>
        /// 初始化
        /// </summary>
        public DbParamPlaceholderProvider(IDbConnection conn, Func<IDataParameter, string> placeholder)
        {
            ConnectionTypeName = conn?.GetType()?.Name ?? throw new ArgumentNullException(nameof(conn));
            _placeholder = placeholder ?? throw new ArgumentNullException(nameof(placeholder));
        }

        private DbParamPlaceholderProvider(string connTypeName, Func<IDataParameter, string> naming)
        {
            ConnectionTypeName = connTypeName ?? throw new ArgumentNullException(nameof(connTypeName));
            _placeholder = naming ?? throw new ArgumentNullException(nameof(naming));
        }

        /// <summary>
        /// 数据库连接类型
        /// </summary>
        public string ConnectionTypeName { get; }

        /// <summary>
        /// 生成参数占位符
        /// </summary>
        public string GetPlaceholder(IDataParameter parameter) => _placeholder(parameter);


        static readonly List<IDbParamPlaceholderProvider> registered = new List<IDbParamPlaceholderProvider>();
        static IDbParamPlaceholderProvider[] _handlers;
        static readonly IDbParamPlaceholderProvider _defaultHandler;

        static DbParamPlaceholderProvider()
        {
            _defaultHandler = new DbParamPlaceholderProvider("default", x => x.ParameterName);
            registered.Add(new DbParamPlaceholderProvider("SQLiteConnection", x => "@" + x.ParameterName));
            registered.Add(new DbParamPlaceholderProvider("SqlConnection", x => "@" + x.ParameterName));
            registered.Add(new DbParamPlaceholderProvider("SqlCeConnection", x => "@" + x.ParameterName));
            registered.Add(new DbParamPlaceholderProvider("NpgsqlConnection", x => "@" + x.ParameterName));
            registered.Add(new DbParamPlaceholderProvider("OracleConnection", x => ":" + x.ParameterName));
            registered.Add(new DbParamPlaceholderProvider("MySqlConnection", x => "?" + x.ParameterName));
            registered.Add(new DbParamPlaceholderProvider("OleIDbConnection", x => "?"));
            registered.AddRange(FeatureManager.Gets<IDbParamPlaceholderProvider>());
            _handlers = Enumerable.Reverse(registered).ToArray();
        }
        /// <summary>
        /// 注册新的提供程序
        /// </summary>
        /// <param name="provider"></param>
        public static void Register(IDbParamPlaceholderProvider provider)
        {
            lock (registered)
            {
                registered.Add(provider);
                _handlers = Enumerable.Reverse(registered).ToArray();
            }
        }

        /// <summary>
        /// 注册新的提供程序
        /// </summary>
        public static void Register(IDbConnection conn, Func<IDataParameter, string> placeholder)
            => Register(new DbParamPlaceholderProvider(conn, placeholder));

        public static IDbParamPlaceholderProvider Get(IDbConnection conn)
        {
            var name = conn.GetType().Name;
            var handlers = _handlers;
            foreach (var handler in handlers)
            {
                if (handler.ConnectionTypeName == name)
                {
                    return handler;
                }
            }
            return _defaultHandler;
        }
    }
}
